﻿namespace Jsl.StyleCop.CSharp.RefactoringRules
{
    using Jsl.StyleCop.CSharp.UnitTesting;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class TestMoveVariableDeclarationToUsageLevel : TestBase<RuleAnalyzer>
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="TestMoveVariableDeclarationToUsageLevel"/> class.
        /// </summary>
        public TestMoveVariableDeclarationToUsageLevel()
            : base(RuleAnalyzer.MoveVariableDeclarationToUsageLevel)
        {
        }
        #endregion Constructors

        [TestMethod]
        public void Variable_is_used_at_the_same_level_as_declared()
        {
            this.TestMethod(
                @"public int Method()
                {
                    int variable = 5;
                    return variable;
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Variable_should_be_moved_into_true_part_of_if_statement()
        {
            this.TestMethod(
                @"public int Method()
                {
                    int variable = 5;
                    if (true)
                    {
                        return variable;
                    }
                }")
                .AssertViolation(3, "The 'variable' variable declaration should be moved to the code block where it is used. The code block starts at line 4.")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Variable_used_inside_a_for_where_variable_is_defined_in_the_for_statement_is_OK()
        {
            this.TestMethod(
                @"public int Method()
                {
                    for (int i = 0; i < 10; i++)
                    {
                        return i;
                    }
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Variable_declared_outside_do_while_and_used_inside_is_OK()
        {
            this.TestMethod(
                @"public void Method()
                {
                    int variable = 5;
                    do
                    {
                        Console.WriteLine(variable);
                    } while (true);
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Variable_declared_outside_a_for_and_used_inside_is_OK()
        {
            this.TestMethod(
                @"public void Method()
                {
                    int variable = 5;
                    for (int i = 0; i < 99; i++)
                    {
                        Console.WriteLine(variable);
                    }
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Variable_declared_outside_a_foreach_and_used_inside_is_OK()
        {
            this.TestMethod(
                @"public void Method()
                {
                    int variable = 5;
                    foreach (var a in b)
                    {
                        Console.WriteLine(variable);
                    }
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Variable_declared_outside_a_while_and_used_inside_is_OK()
        {
            this.TestMethod(
                @"public void Method()
                {
                    int variable = 5;
                    while (true)
                    {
                        Console.WriteLine(variable);
                    }
                }")
                .NoMoreViolations();
        }

        [TestMethod]
        public void Hoisted_variables_are_ignored()
        {
            this.TestMethod(
                @"public int Method()
                {
                    int variable = 5;
                    Method(() => variable + 1);
                }")
                .NoMoreViolations();
        }
    }
}